package com.huawei.deveco.common.security.util;

import java.util.List;
import java.util.Optional;

public class PasswordValidator {
    private static final int MIN_LENGTH = 8;

    private static final int MIN_NUM_CHAR_TYPE = 2;

    public static boolean checkPasswordStrength(char[] password, List<String> errors) {
        Optional<List<String>> msg = Optional.ofNullable(errors);
        if (password == null || password.length < 8) {
            msg.ifPresent(list -> list.add("incorrect.password.length"));
            return false;
        }
        int countBits = countCharType(password);
        boolean isPassed = true;
        if ((countBits & 0x1) == 1) {
            isPassed = false;
            msg.ifPresent(list -> list.add("incorrect.password.other"));
        }
        if (countValidCharType(countBits) < 2) {
            isPassed = false;
            msg.ifPresent(list -> list.add("incorrect.password.strength"));
        }
        return isPassed;
    }

    public static void checkPasswordStrength(char[] password) throws SecurityException {
        if (password == null || password.length < 8)
            throw new SecurityException("incorrect.password.length");
        int countBits = countCharType(password);
        if ((countBits & 0x1) == 1)
            throw new SecurityException("incorrect.password.other");
        if (countValidCharType(countBits) < 2)
            throw new SecurityException("incorrect.password.strength");
    }

    private static int countValidCharType(int bits) {
        int validBits = bits >> 1;
        int count = 0;
        while (validBits > 0) {
            count += validBits & 0x1;
            validBits >>= 1;
        }
        return count;
    }

    private static int countCharType(char[] password) {
        int typeBits = 0;
        for (char ch : password) {
            if (Character.isDigit(ch)) {
                typeBits |= 0x2;
            } else if (Character.isLowerCase(ch)) {
                typeBits |= 0x4;
            } else if (Character.isUpperCase(ch)) {
                typeBits |= 0x8;
            } else if (isSpecialChar(ch)) {
                typeBits |= 0x10;
            } else {
                typeBits |= 0x1;
                break;
            }
        }
        return typeBits;
    }

    private static boolean isSpecialChar(char ch) {
        String specialChars = "`~!@#$%^&*()-_=+\\|[{}];:'\",<.>/? ";
        return specialChars.contains(String.valueOf(ch));
    }
}
